/**
 ******************************************************************************
 * @file    AlarmList.h
 * @author  Zxp
 * @version V1.0.0
 * @date    2021-03-01
 * @brief   闹钟列表
 ******************************************************************************
 */

#ifndef _ALARM_LIST
#define _ALARM_LIST

#include <Arduino.h>
#include <DS3231.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>

#define UPDATE_TIME_WAY_BY_RTC 1 /* 使用RTC的方式更新 */

enum OptFunParamENUM
{
    OptParam_Auto = 0,  ///< 自动控制
    OptParam_Manual,    ///< 手动控制
    OptParam_Remote,    ///< 远程控制
    OptParam_Test,      ///< 测试控制
    OptParam_Limit,     ///< 操作函数参数的最大数目
};

enum OptFunIndexENUM
{
    OptIndex_OpenLight = 0,
    OptIndex_CloseLight,
    OptIndex_Limit,  ///< 操作函数的最大数目
};
typedef void (*OptFun)(int);

typedef struct tagOptFun
{
    const char *info;
    OptFun function;
} OptFunType;

typedef struct tagAlarmType
{
    int8_t date;    ///< 一个月中的哪一天
    int8_t day;     ///< 一周中的哪一天响,其中,1代表周一,7代表周天
    int8_t hour;    ///< 闹铃的小时数
    int8_t minute;  ///< 闹铃的分钟数
    int8_t cnt;  ///< 闹钟剩余次数,小于0表示无限制,大于零小于一百表示倒计数中,减为0后删除此闹钟
    uint8_t optIndex;           ///< 操作的下标
    struct tagAlarmType *next;  ///< 链表后指针
    struct tagAlarmType *pre;   ///< 链表前指针
} AlarmType;

extern void openLight(int state);
extern void closeLight(int state);
const OptFunType OptFunTbl[] = {{"open light", openLight}, {"close light", closeLight}};

// extern DS3231 rtc;

enum UpdateTimeWay
{
    eUpdateTime_Ticker = 0,  ///< 使用内部计时器方式更新时间
    eUpdateTime_RTC,         ///< 使用外部RTC芯片方式更新时间
};

class CurrentTime
{
private:
    DS3231 rtcDs;

public:
    CurrentTime();
    CurrentTime(time_t ts);
    CurrentTime(int16_t year, int8_t month, int8_t date, int8_t day, int8_t hour, int8_t minute,
                int8_t second);

    /**
     * @brief   内部定时器调用此方法,尽量一秒调用一次
     * @param   None
     * @return  None
     */
    void increaseTimeStamp();

    /**
     * @brief   通过时间戳更新时间
     * @param   ts: 不调形参时使用内部tickerTs作为时间戳,填形参时使用该形参作为时间戳
     * @return  None
     */
    void updateTimeByTimeStamp(time_t ts = 0);

    /**
     * @brief   通过读取RTC来更新时间
     * @param   None
     * @return  None
     */
    void updateTimeByRTC();

    /**
     * @brief   会根据判断RTC是否可用,若不可用,则使用时间戳方式更新时间,反之使用RTC时间
     * @param   None
     * @return  None
     */
    void updateTime();
    ~CurrentTime();

    int16_t year;
    int8_t month;
    int8_t date;
    int8_t day;
    int8_t hour;
    int8_t minute;
    int8_t second;
    int8_t tickCnt;
    uint8_t updateWay;  ///< 更新方式
    uint32_t timeStamp;
    time_t tickerTs;
};

class AlarmList
{
private:
    /* data */
    size_t len;
    AlarmType *head;
    AlarmType *tail;

public:
    AlarmList(/* args */);
    ~AlarmList();
    int add(AlarmType *);
    int add(int8_t, int8_t, int8_t, int8_t, int8_t, uint8_t);
    int remove(AlarmType *);
    int remove(AlarmType &);
    int compare(AlarmType *, AlarmType *);
    AlarmType *compare(CurrentTime &current);
    AlarmType *compare(AlarmType &);
    AlarmType *getHead()
    {
        return head;
    };
    size_t getLength(void)
    {
        return len;
    }
};

#endif  // #ifndef _ALARM_LIST
